// created by noellynch
// May 14, 2011

package com.gruntdb.objects;

import java.io.File;
import java.nio.ByteBuffer;

import com.gruntdb.core.stubs.IGruntDBIndex;
import com.gruntdb.core.stubs.IStorageEngine;

public class GruntDBIndexStore {
	private static final long INITIAL_IDX_CAPACITY = 100;

	private		GruntDBFile					mcl_file;
	private		GruntDBFileSeek				mcl_addSeek;
	
	private		ByteBuffer					mcl_idxBuffer;
	
	// current insertion offset
	private		long				ml_currentID = 0;
	private		long				ml_indexCount = 0;
	
	private		IStorageEngine				mcl_storageEngine;
	private		boolean						mb_dirty;
	
	public	GruntDBIndexStore(IStorageEngine cl_dataStore) {
		super();
		mcl_storageEngine = cl_dataStore;
	}

	public	boolean		isSpaceForNewIndex() throws Exception{
		if((ml_indexCount * mcl_storageEngine.getSizeofIndex()) >= mcl_file.size()){
			return false;
		}
		
		return true;
	}
	
	public	ByteBuffer		getBuffer() {
		synchronized (mcl_idxBuffer) {
			return mcl_idxBuffer;
		}
	}
	
	public		void	initIndexFile() {
		File		lcl_f = new File(mcl_storageEngine.getLocation(), getIndexFileName(mcl_storageEngine.getFileReferenceName()));
		try {
			mcl_file = new GruntDBFile(lcl_f);
			mcl_addSeek = mcl_file.getASeek();
			ml_indexCount = mcl_file.size() / mcl_storageEngine.getSizeofIndex();
			mcl_idxBuffer = mcl_file.getMap(0, mcl_file.size());
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public	void	setCurrentID(long i_id) {
		ml_currentID = i_id;
	}
	
	public	boolean		isDirty() {
		synchronized (this) {
			return mb_dirty;
		}
	}
	
	public	void		clearDirty() {
		synchronized (this) {
			mb_dirty = false;
		}
	}
	
	public	long	getCurrentID() {
		synchronized (this) {
			return ml_currentID;
		}
	}
	
	public	long	getNextPossibleID() {
		return ml_currentID + 1;
	}
	
	public	void	close() {
		try {
			System.out.println("closing channel and file...");
			mcl_file.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public	long	getSizeOfIndexStore() throws Exception {
		return mcl_file.size();
	}
	
	public	void	allocateNewBlock() throws Exception {
		synchronized (mcl_file) {
			System.out.println("allocating new block for index storage, existing capacity = " + mcl_file.size());
			mcl_file.allocate((int)(INITIAL_IDX_CAPACITY * mcl_storageEngine.getSizeofIndex()));
			
			System.out.println("block allocated, index store capacity is now = " + mcl_file.size());
			mcl_idxBuffer = mcl_file.getMap(0, mcl_file.size());
		}
		
	}
	
	public	void	addNewIndex(IGruntDBIndex cl_index) {
		synchronized (this) {
			// move to next entry
			mcl_idxBuffer.position((int)mcl_addSeek.getCurrentSeek());
			
			// put the value
			cl_index.put(mcl_idxBuffer);
			
			// increment our seek
			mcl_addSeek.offset(mcl_storageEngine.getSizeofIndex());
			
			// increment our counters
			ml_indexCount++;
			ml_currentID++;
		}	
	}
	
	public	GruntDBIndexIterator		iterator() {
		return new GruntDBIndexIterator(this);
	}
	
	protected	long		getSizeofIndex() {
		return mcl_storageEngine.getSizeofIndex();
	}
	
	protected	GruntDBFileSeek		getASeek() {
		return mcl_file.getASeek();
	}
	
	protected	IGruntDBIndex		getAnIndexInstance() {
		try {
			return (IGruntDBIndex)mcl_storageEngine.getIndexType().newInstance();
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return null;
	}
		
	static	final	public	String	getIndexFileName(String str_name) {
		return str_name + ".idx";
	}	
}
